//=====================================================================
//
//  Description:
//  
//  The module to implement the core's CSRs
//
// ====================================================================
`include "defines.v"

module csr(
    input   			clk,
    input   			rst,
    input  				csr_en,
    input   			csr_wr_en,
    input   			csr_rd_en,
    input  [12-1:0] 	csr_idx,
	input  [`XLEN-1:0] 	csr_wr_data,
    output [`XLEN-1:0] 	csr_rd_data
  );


// Only toggle when need to read or write to save power
wire write_csr = csr_en & csr_wr_en;
wire read_csr =  csr_en & csr_rd_en;

//0x320 mcountinhibit MRW
wire sel_mcountinhibit = (csr_idx == 12'h320);
wire wr_mcountinhibit = sel_mcountinhibit & write_csr ;
wire rd_mcountinhibit = sel_mcountinhibit & read_csr;

reg[`XLEN-1:0]	 mcountinhibit_reg;
wire[`XLEN-1:0]	 mcountinhibit_next;
assign mcountinhibit_next[31:3]  = 29'b0 ;
assign mcountinhibit_next[2]  = wr_mcountinhibit ? csr_wr_data[2] : mcountinhibit_reg[2] ;  //ir
assign mcountinhibit_next[1]  = 1'b0 ;
assign mcountinhibit_next[0]  = wr_mcountinhibit ? csr_wr_data[0] : mcountinhibit_reg[0] ;  //cy
   
always @(posedge clk or posedge rst)
begin
	if (rst)
		mcountinhibit_reg <= 32'b0 ;
	else if (wr_mcountinhibit )
		mcountinhibit_reg <= mcountinhibit_next;

end


//////////////////////////

// 0xb00 MRW mcycle 
// 0xb02 MRW minstret 
// 0xb80 MRW mcycleh
// 0xb82 MRW minstreth 
wire sel_mcycle    = (csr_idx == 12'hB00);
wire sel_mcycleh   = (csr_idx == 12'hB80);
wire sel_minstret  = (csr_idx == 12'hB02);
wire sel_minstreth = (csr_idx == 12'hB82);

wire wr_mcycle     = write_csr & sel_mcycle   ;
wire wr_mcycleh    = write_csr & sel_mcycleh  ;
wire wr_minstret   = write_csr & sel_minstret ;
wire wr_minstreth  = write_csr & sel_minstreth;

wire rd_mcycle     = read_csr & sel_mcycle   ;
wire rd_mcycleh    = read_csr & sel_mcycleh  ;
wire rd_minstret   = read_csr & sel_minstret ;
wire rd_minstreth  = read_csr & sel_minstreth;


reg [`XLEN-1:0] mcycle_reg     ;
reg [`XLEN-1:0] mcycleh_reg    ;
wire [`XLEN-1:0] mcycle_next   ;
wire [`XLEN-1:0] mcycleh_next  ;

reg [`XLEN-1:0] minstret_reg   ;
reg [`XLEN-1:0] minstreth_reg  ;
wire [`XLEN-1:0] minstret_next ;
wire [`XLEN-1:0] minstreth_next;



//We need to use the always-on clock for this counter

assign {mcycleh_next,mcycle_next} = wr_mcycle ? {mcycleh_reg,csr_wr_data} : wr_mcycleh ?
											 {csr_wr_data , mcycle_reg } : mcountinhibit_reg[0] ? {mcycleh_reg,mcycle_reg} 
														: {mcycleh_reg,mcycle_reg}  + 1'b1 ;

always @(posedge clk or posedge rst)
begin
	if (rst)
	begin
		mcycle_reg <= 32'b0 ;
		mcycleh_reg <= 32'b0 ;
	end
	else 
	begin
		mcycle_reg <= mcycle_next;
		mcycleh_reg <= mcycleh_next;
	end

end

//0xb02 minstret  0xb82 minstreth  指令完成计数器 
assign {minstreth_next,minstret_next} = wr_minstret ?  {minstreth_reg , csr_wr_data} : wr_minstreth ? 
											 {csr_wr_data , minstret_reg } : ((~mcountinhibit_reg[2])) ? {minstreth_reg,minstret_reg}  + 1'b1 
												:{minstreth_reg,minstret_reg} ;

always @(posedge clk or posedge rst)
begin
	if (rst)
	begin
		minstret_reg <= 32'b0 ;
		minstreth_reg <= 32'b0 ;
	end
	else if(wr_minstret | wr_minstreth)
	begin
		minstret_reg <= minstret_next;
		minstreth_reg <= minstreth_next;
	end

end
/////////////////////////////////////////////////////////////////////

assign csr_rd_data = `XLEN'b0 
               //| ({`XLEN{rd_ustatus  }} & csr_ustatus  )
               | ({`XLEN{rd_mcycle   }} & mcycle_reg   )
               | ({`XLEN{rd_mcycleh  }} & mcycleh_reg  )
               | ({`XLEN{rd_minstret }} & minstret_reg )
               | ({`XLEN{rd_minstreth}} & minstreth_reg)
               | ({`XLEN{rd_mcountinhibit}} & mcountinhibit_reg)
               ;


endmodule

